<template>
    <a-dropdown
        :popPlacement="popPlacement"
        :useTargetWidth="true"
        :maxHeight="maxHeight"
        class="a-input-tree-multi"
        :class="[`color-${color}`]"
        v-model:popShown="popShown"
        :trigger="'none'"
    >
        <a-control-group class="a-input-tree-multi">
            <a-input-string
                class="c-w-100"
                :color="myColor"
                :size="mySize"
                :sharp="mySharp"
                :disabled="myDisabled"
                :value="displayText"
                :placeholder="placeholder"
                :readonly="true"
                :clearable="clearable"
                :isInner="true"
                @click="popShown = !popShown"
                @clear="clear"
            ></a-input-string>
            <a-button
                v-if="attachButtonShown"
                class="c-f-shrink-0"
                :color="myColor"
                :size="mySize"
                :sharp="mySharp"
                :disabled="myDisabled"
                :square="true"
                ref="btn"
                @click="popShown = !popShown"
                ><span class="fa fa-fw fa-angle-down"></span></a-button
        ></a-control-group>

        <template v-slot:pop>
            <a-tree
                :items="items"
                :getItemsFunc="myGetItemsFunc"
                :getKeyFunc="getTextFunc"
                :getIsFolderFunc="getIsFolderFunc"
                :getIsItemOpenedFunc="isItemOpened"
                class="pop"
                :class="[
                    !mySharp ? `c-round-${mySize}` : '',
                    ` c-shadow-${mySize}`,
                ]"
            >
                <template
                    v-slot:foldName="{
                        item,
                        parent,
                        depth,
                        index,
                        itemCount,
                        opened,
                    }"
                >
                    <div class="c-f-h c-f-start-center c-w-100">
                        <template v-if="parentPathMapKeyByItem.get(item)">
                            <a-line-header
                                v-for="(_p, i) in parentPathMapKeyByItem.get(
                                    item
                                )"
                                :color="myColor"
                                :top="
                                    parentPathMapKeyByItem.get(item)[i + 1] ==
                                        null ||
                                    !isLastItemSet.has(
                                        parentPathMapKeyByItem.get(item)[i + 1]
                                    )
                                "
                                :right="
                                    i ==
                                    parentPathMapKeyByItem.get(item).length - 1
                                "
                                :bottom="
                                    !isLastItemSet.has(
                                        parentPathMapKeyByItem.get(item)[
                                            i + 1
                                        ] ?? item
                                    )
                                "
                                class="c-f-shrink-0"
                            ></a-line-header>
                        </template>
                        <a-control-group :block="true" class="c-f-grow-1">
                            <a-button
                                :color="myColor"
                                :size="mySize"
                                :sharp="true"
                                :plain="true"
                                :square="true"
                                @click="toggleOpenItem(item)"
                                class="c-f-shrink-0 c-position-relative"
                            >
                                <span
                                    class="fa fa-fw fa-folder"
                                    v-if="!opened"
                                ></span>
                                <span
                                    class="fa fa-fw fa-folder-open"
                                    v-else
                                ></span>
                                <span
                                    class="dot"
                                    v-if="selectedPathSet.has(item)"
                                ></span>
                            </a-button>
                            <a-input-check-box-single
                                v-if="canSelectFolder"
                                :color="myColor"
                                :size="mySize"
                                :sharp="true"
                                :disabled="itemDisabled(item, parent)"
                                :block="true"
                                :plain="true"
                                :value="selectedItemSet.has(item)"
                                :isInner="true"
                                @click="clickItem(item)"
                                class="c-f-h c-f-between-center"
                            >
                                <template v-slot:prepend>
                                    <span>{{ getTextFunc(item) }}</span>
                                </template>
                            </a-input-check-box-single>
                            <div
                                v-else
                                class="c-f-h c-f-between-center c-cursor-default c-w-100"
                                :class="[
                                    `c-height-${mySize}`,
                                    `c-font-size-${mySize}`,
                                    `c-front-color-${myColor}-reverse`,
                                    `c-p-h-${mySize}`,
                                ]"
                            >
                                <span>{{ getTextFunc(item) }}</span>
                                <span
                                    class="fa fa-fw fa-check"
                                    v-if="selectedItemSet.has(item)"
                                ></span>
                            </div>
                        </a-control-group>
                    </div>
                </template>
                <template
                    v-slot:file="{ item, parent, depth, index, itemCount }"
                >
                    <div class="c-f-h c-f-start-center c-w-100">
                        <template v-if="parentPathMapKeyByItem.get(item)">
                            <a-line-header
                                v-for="(_p, i) in parentPathMapKeyByItem.get(
                                    item
                                )"
                                :color="myColor"
                                :top="
                                    parentPathMapKeyByItem.get(item)[i + 1] ==
                                        null ||
                                    !isLastItemSet.has(
                                        parentPathMapKeyByItem.get(item)[i + 1]
                                    )
                                "
                                :right="
                                    i ==
                                    parentPathMapKeyByItem.get(item).length - 1
                                "
                                :bottom="
                                    !isLastItemSet.has(
                                        parentPathMapKeyByItem.get(item)[
                                            i + 1
                                        ] ?? item
                                    )
                                "
                                class="c-f-shrink-0"
                            ></a-line-header>
                        </template>
                        <div
                            class="c-f-h c-f-center-center c-f-shrink-0"
                            :class="[
                                `c-square-${mySize}`,
                                `c-front-color-${myColor}-reverse`,
                            ]"
                        >
                            <span class="fa fa-fw fa-file"></span>
                        </div>
                        <a-input-check-box-single
                            :color="myColor"
                            :size="mySize"
                            :sharp="true"
                            :disabled="itemDisabled(item, parent)"
                            :block="true"
                            :plain="true"
                            :value="selectedItemSet.has(item)"
                            :isInner="true"
                            @click="clickItem(item)"
                            class="c-f-h c-f-between-center"
                        >
                            <template v-slot:prepend>
                                <span>{{ getTextFunc(item) }}</span>
                            </template>
                        </a-input-check-box-single>
                    </div>
                </template>
            </a-tree>
        </template>
    </a-dropdown>
</template>

<style lang="scss" scoped>
@import "../scss/vars";

.pop {
    background-color: $defaultBgColor;
}
.dot {
    background-color: #ff0000;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    position: absolute;
    right: 0;
    top: 0;
}
</style>

<script>
import AInputString from './AInputString.vue'
import AButton from './AButton.vue'
import AControlGroup from './AControlGroup.vue'
import ADropdown from './ADropdown.vue'
import ATree from './ATree.vue'
import ALineHeader from './ALineHeader.vue'
import AInputCheckBoxSingle from './AInputCheckBoxSingle.vue'
import inputMixin from "../mixins/inputMixin"

export default {
    name: 'AInputTreeMulti',
    components: { AInputString, AButton, AControlGroup, ADropdown, ATree, ALineHeader, AInputCheckBoxSingle },
    mixins: [inputMixin],
    props: {
        value: {
            type: Array,
            default: [],
        },
        /**
         * 对齐到target的位置
         */
        popPlacement: {
            type: String,
            default: 'bottom'
        },
        items: {
            type: Array,
            default: [],
        },
        getItemsFunc: {
            type: Function,
            default: a => a.items,
        },
        getIsFolderFunc: {
            type: Function,
            default: a => a.type == 0,
        },
        getTextFunc: {
            type: Function,
            default: a => a.text,
        },
        separator: {
            type: String,
            default: ' ',
        },
        useShortDisplayText: {
            type: Boolean,
            default: false,
        },
        getValueFunc: {
            type: Function,
            default: a => a.value,
        },
        getDisabledFunc: {
            type: Function,
            default: a => a.disabled,
        },
        canSelectFolder: {
            type: Boolean,
            default: false,
        },
        clearable: {
            type: Boolean,
            default: true,
        },
        maxHeight: {
            type: Number,
            default: null
        },
        placeholder: {
            type: String,
            default: null
        },
        attachButtonShown: {
            type: Boolean,
            default: true,
        },
    },
    data() {
        return {
            popShown: false,
            openedItemSet: new Set(),
        }
    },
    computed: {
        displayText() {
            let selectedItems = this.selectedItemList
            if (selectedItems.length == 0) {
                return ''
            }
            if (this.useShortDisplayText) {
                return this.getTextFunc(selectedItems[0]) + (selectedItems.length > 1 ? this.$t('AInputTreeMulti.ItemsIntotal', [selectedItems.length]) : '')
            } else {
                return selectedItems.map(a => this.getTextFunc(a)).join(this.separator)
            }
        },
        selectedItemList() {
            let selectedItems = this.value.map(a => this.findSelectedItem(this.items, a)).filter(a => a)
            return selectedItems
        },
        selectedItemSet() {
            return new Set(this.selectedItemList)
        },
        selectedPathList() {
            let list = []
            this.selectedItemList.forEach(item => {
                let selectedPathList = [item]
                let parent = this.parentMapKeyByItem.get(item)
                while (parent) {
                    selectedPathList.unshift(parent)
                    parent = this.parentMapKeyByItem.get(parent)
                }
                list = [...list, ...selectedPathList]
            })
            return Array.from(new Set(list))
        },
        selectedPathSet() {
            return new Set(this.selectedPathList)
        },
        allItems() {
            let allItems = [...this.items]
            let toBeComputedItems = [...this.items]
            while (toBeComputedItems.length) {
                let toBeComputedItem = toBeComputedItems.shift()
                if (this.getIsFolderFunc(toBeComputedItem)) {
                    let subItems = this.getItemsFunc(toBeComputedItem)
                    allItems = [...allItems, ...subItems]
                    toBeComputedItems = [...toBeComputedItems, ...subItems]
                }
            }
        },
        itemsMapKeyByParent() {
            let map = new Map()
            let toBeComputedItems = [...this.items]
            while (toBeComputedItems.length) {
                let toBeComputedItem = toBeComputedItems.shift()
                if (this.getIsFolderFunc(toBeComputedItem)) {
                    let subItems = this.getItemsFunc(toBeComputedItem)
                    map.set(toBeComputedItem, subItems)
                    toBeComputedItems = [...toBeComputedItems, ...subItems]
                }
            }
            return map
        },
        parentMapKeyByItem() {
            let map = new Map()
            this.itemsMapKeyByParent.forEach((items, parent) => {
                items.forEach(a => map.set(a, parent))
            })
            return map
        },
        parentPathMapKeyByItem() {
            let map = new Map()
            this.parentMapKeyByItem.forEach((parent, item) => {
                let parentPath = []
                let _p = parent
                while (_p) {
                    parentPath.unshift(_p)
                    _p = this.parentMapKeyByItem.get(_p)
                }
                map.set(item, parentPath)
            })
            return map
        },
        isLastItemSet() {
            let set = new Set()
            this.itemsMapKeyByParent.forEach(items => {
                let lastItem = items[items.length - 1]
                if (lastItem) {
                    set.add(lastItem)
                }
            })
            return set
        },
    },
    methods: {
        input(val) {
            this.$emit('update:value', val)
        },
        clear() {
            this.input([])
        },
        clickItem(item) {
            let itemValue = this.getValueFunc(item)
            if (this.selectedItemSet.has(item)) {
                this.input(this.value.filter(a => a != itemValue))
            } else {
                this.input([...this.value, itemValue])
            }
        },
        toggleOpenItem(item) {
            if (this.isItemOpened(item)) {
                this.openedItemSet.delete(item)
            } else {
                this.openedItemSet.add(item)
            }
        },
        isItemOpened(item) {
            return this.openedItemSet.has(item)
        },
        findSelectedItem(items, value) {
            for (let i = 0; i < items.length; i++) {
                let item = items[i]
                if (this.getValueFunc(item) == value) {
                    return item
                }
                if (this.getIsFolderFunc(item)) {
                    let itemInSubDir = this.findSelectedItem(this.myGetItemsFunc(item), value)
                    if (itemInSubDir != null) {
                        return itemInSubDir
                    }
                }
            }
            return null
        },
        itemDisabled(item) {
            if (this.disabled == true) {
                return true
            }
            if (this.getDisabledFunc(item)) {
                return true
            }
            let parent = this.parentMapKeyByItem.get(item)
            if (parent != null && this.itemDisabled(parent)) {
                return true
            }
            return false
        },
        myGetItemsFunc(item) {
            return this.itemsMapKeyByParent.get(item)
        },
        reset() {
            this.openedItemSet = new Set()
        },
    },
}
</script>